package com.cst.intercepterdemo.chain.builder;

import com.cst.intercepterdemo.chain.IIntercepterChain;
import com.cst.intercepterdemo.chain.IntercepterChain;
import com.cst.intercepterdemo.chain.expression.IExpression;
import com.cst.intercepterdemo.chain.expression.parser.IExpressionParser;
import com.cst.intercepterdemo.chain.node.AndChainNode;
import com.cst.intercepterdemo.chain.node.DefaultChainNode;
import com.cst.intercepterdemo.chain.node.IIntercepterChainNode;
import com.cst.intercepterdemo.chain.node.OrChainNode;
import com.cst.intercepterdemo.exceptions.ExpressionNotCorrectException;
import com.cst.intercepterdemo.exceptions.ExpressionNotExistException;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <ul>
 * <li>文件名称 : com.cst.intercepterdemo.chain.builder.AbstractChainBuilder
 * </li>
 * <li>版权所有 : 版权所有(C)2016-2020</li>
 * <li>公 司 : CST</li>
 * <li>创建时间 : 2016/12/2</li>
 * <li>修改记录 : </li>
 * </ul>
 * 类说明：基于表达式的拦截器责任链构建抽象类
 * 按表达式从左到右构成链
 * 表达式由逗号，小括号构成，如：aa||aa||(bbb&&bbb),dddd,eeee(eee(aaa))dd
 *
 * @author Allen
 * @version 1.0
 */
public abstract class AbstractExpressionBaseChainBuilder
        extends AbstractBeanChainBuilder {

    private static final String AND_SIGN = "&&";
    private static final String OR_SIGN = "||";
    private static final String SPLITTER = ",";

    public static final Pattern REPLACEMENT = Pattern.compile("\\{[0-9]+\\}");

    @Override
    public List<IIntercepterChain> buildAll() {
        List<IIntercepterChain> targetList = new ArrayList<>();
        List<ExpressionData> allExpressionString = getAllExpressionString();
        for (ExpressionData stringObjectMap : allExpressionString) {
            targetList.add(buildSingle(stringObjectMap.getKey()
                    ,stringObjectMap.getExpression()));
        }
        return targetList;
    }

    /**
     * 验证责任链
     */
    protected void validateChain(IIntercepterChainNode firstNode){
        //TODO
    }

    @Override
    public IIntercepterChain build(String key) {
        String expressionString = getExpressionString(key);

        if(StringUtils.isEmpty(expressionString)){
            throw new ExpressionNotExistException(key);
        }
        return buildSingle(key,expressionString);
    }

    /**
     * 构建责任链
     * @param expressionString
     * @return
     */
    private IIntercepterChain buildSingle(String key,String expressionString){
        //解析表达式
        IExpression expression = getExpressionParser(key).parse(expressionString);
        //构建链
        IIntercepterChainNode firstNode = constructIntercepterChain(expression,expressionString.toCharArray());
        //验证链是否合法
        validateChain(firstNode);
        return new IntercepterChain(firstNode,key);
    }

    /**
     * 组装责任链
     * @param expression 表达式
     * @param expressionString 表达式全字符
     * @return
     */
    private IIntercepterChainNode constructIntercepterChain(IExpression expression,
                                                        char[] expressionString
                                                        ){
        if(expression.hasSubExpression()){ //有子表达式
            Map<IExpression,IIntercepterChainNode> subNodeMap = new HashMap<>();
            List<IExpression> subExpressions = expression.getSubExpression();
            for (IExpression subExpression : subExpressions) {
                subNodeMap.put(subExpression,constructIntercepterChain(subExpression, expressionString));
            }
            return constructComplextIntercepterChain(expression,expressionString,subNodeMap);
        }else{ //无子表达式
            return constructPureIntercepterChain(expression.getExpression(expressionString));
        }
    }

    /**
     * 构建存在子Node的拦截器
     * @param expressionString
     * @param subNodes
     * @return
     */
    private IIntercepterChainNode constructComplextIntercepterChain(IExpression currentExpression,
                                                                    char[] expressionString,
                                                                    Map<IExpression,IIntercepterChainNode> subNodes) {

        String workingExpressionString = currentExpression.getExpression(expressionString);

        //将字表达式替换为${number}
        List<IExpression> subExpression = currentExpression.getSubExpression();
        int replaceIndex = 0;
        Map<String,IExpression> replacementMap = new HashMap<>();
        for (int i = subExpression.size() - 1; i >= 0; i--) {
            IExpression currentSubExpression = subExpression.get(i);
            String replacement = "${"+(replaceIndex++)+"}";
            replacementMap.put(replacement,currentSubExpression);
            workingExpressionString = workingExpressionString.substring(0,currentSubExpression.getStartIndex()-currentExpression.getStartIndex()-1)
                                    + replacement
                                    + workingExpressionString.substring(currentSubExpression.getEndIndex()-currentExpression.getStartIndex(),workingExpressionString.length()-1);
        }

        //分隔表达式并逐个处理
        List<IIntercepterChainNode> tempIntercepterNodeList = new ArrayList<>();

        String[] expressions = workingExpressionString.split(SPLITTER);
        for (String expression : expressions) {
            if (hasReplacement(expression)) {
                IIntercepterChainNode currentNode = null;
                ExpressionType expressionType = getExpressionType(expression);
                switch (expressionType){
                    case AND : currentNode = constructMetaAndIntercepterNode(expression,replacementMap,subNodes);break;
                    case OR : currentNode = constructMetaOrIntercepterNode(expression,replacementMap,subNodes);break;
                    case DEFAULT : currentNode = constructMetaDefaultIntercepterNode(expression,replacementMap,subNodes);
                }
                tempIntercepterNodeList.add(currentNode);
            } else {
                tempIntercepterNodeList.add(constructPureIntercepterChain(expression));
            }
        }
        IIntercepterChainNode firstNode = null;
        for (IIntercepterChainNode iIntercepterChainNode : tempIntercepterNodeList) {
            if(firstNode==null){
                firstNode = iIntercepterChainNode;
            }else{
                firstNode.setNext(iIntercepterChainNode);
            }
        }
        return tempIntercepterNodeList.get(0);
    }

    /**
     * 构建无子表达式的拦截器
     * @param expressionString
     * @return
     */
    private IIntercepterChainNode constructPureIntercepterChain(String expressionString){
        String[] expressions = expressionString.split(SPLITTER);

        IIntercepterChainNode firstNode = null;
        IIntercepterChainNode workNode = null;
        for (String singleExpression : expressions) {

            ExpressionType expressionType = getExpressionType(singleExpression);

            IIntercepterChainNode currentNode = null;
            switch (expressionType){
                case AND : currentNode = constructMetaAndIntercepterNode(singleExpression,null,null);break;
                case OR : currentNode = constructMetaOrIntercepterNode(singleExpression,null,null);break;
                case DEFAULT : currentNode = constructMetaDefaultIntercepterNode(singleExpression,null,null);
            }
            if(firstNode == null){
                firstNode = currentNode;
                workNode = currentNode;
            }else{
                workNode.setNext(currentNode);
                workNode = currentNode;
            }
        }
        return firstNode;
    }

    /**
     * 构建默认拦截器节点
     * @param expressionString
     * @return
     */
    private IIntercepterChainNode constructMetaDefaultIntercepterNode(String expressionString,
                                                                      Map<String,IExpression> replacementMap,
                                                                      Map<IExpression,IIntercepterChainNode> nodes){
        if(replacementMap==null && nodes==null){
            return new DefaultChainNode(getIntercepterByName(expressionString.trim()));
        }else{
            return nodes.get(replacementMap.get(expressionString.trim()));
        }
    }

    /**
     * 构建AND拦截器节点
     * @param expressionString
     * @return
     */
    private IIntercepterChainNode constructMetaAndIntercepterNode(String expressionString,
                                                                  Map<String,IExpression> replacementMap,
                                                                  Map<IExpression,IIntercepterChainNode> nodes){
        String[] andExpressions = expressionString.split(AND_SIGN);
        return new AndChainNode(buildAndOrIntercepters(andExpressions,replacementMap,nodes));
    }
    /**
     * 构建Or拦截器节点
     * @param expressionString
     * @return
     */
    private IIntercepterChainNode constructMetaOrIntercepterNode(String expressionString,
                                                                 Map<String,IExpression> replacementMap,
                                                                 Map<IExpression,IIntercepterChainNode> nodes){
        String[] orExpressions = expressionString.split("\\|\\|");
        return new OrChainNode(buildAndOrIntercepters(orExpressions,replacementMap,nodes));
    }

    private IIntercepterChainNode[] buildAndOrIntercepters(String[] expressions,
                                                           Map<String,IExpression> replacementMap,
                                                           Map<IExpression,IIntercepterChainNode> nodes){
        IIntercepterChainNode[] targetArray = new IIntercepterChainNode[expressions.length];
        for (int i = 0; i < expressions.length; i++) {
            String expression = expressions[i];
            if(replacementMap==null && nodes==null) {
                targetArray[i] = constructMetaDefaultIntercepterNode(expression,null,null);
            }else{
                IIntercepterChainNode chainNode = null;
                if(hasReplacement(expression)){
                    chainNode = nodes.get(replacementMap.get(expression.trim()));
                }else{
                    chainNode = constructMetaDefaultIntercepterNode(expression,null,null);
                }
                targetArray[i] = chainNode;
            }
        }
        return targetArray;
    }

    /**
     * 判断传入字符串是否包含替代符
     * @param expression
     * @return
     */
    private boolean hasReplacement(String expression){
        Matcher matcher = REPLACEMENT.matcher(expression);
        return matcher.find();
    }

    /**
     * 获取表达式类型
     * @param expression
     * @return
     */
    private ExpressionType getExpressionType(String expression){
        int andIndex = expression.indexOf(AND_SIGN);
        int orIndex = expression.indexOf(OR_SIGN);

        if(andIndex>-1 && orIndex>-1){
            throw new ExpressionNotCorrectException("'and' 'or' exists in same sub expression");
        }else if(andIndex>-1){
            return ExpressionType.AND;
        }else if(orIndex>-1){
            return ExpressionType.OR;
        }else{
            return ExpressionType.DEFAULT;
        }


    }

    /**
     * 获取指定表达式数据
     * @param key
     * @return
     */
    protected abstract String getExpressionString(String key);

    /**
     * 获取所有表达式数据
     * @return
     */

    protected abstract List<ExpressionData> getAllExpressionString();

    /**
     * 获取表达式解析器
     * @param key key
     * @return
     */
    protected abstract IExpressionParser getExpressionParser(String key);

    /**
     * 表达式数据传输类
     */
    protected static class ExpressionData{
        private String key;
        private String expression;

        public ExpressionData(String key, String expression) {
            this.key = key;
            this.expression = expression;
        }
        public String getKey() {
            return key;
        }

        public String getExpression() {
            return expression;
        }
    }

    /**
     * 表达式类型
     */
    private enum ExpressionType{
        DEFAULT,OR,AND
    }

}
